package cn.bearspark.user.provider.service.impl;

import cn.bearspark.common.aop.autoparse.host.AutoParseHost;
import cn.bearspark.common.enumeration.JwtClaimsKeyEnum;
import cn.bearspark.common.dto.ResponseDTO;
import cn.bearspark.common.util.*;
import cn.bearspark.idgenerator.enumeration.IdCodeEnum;
import cn.bearspark.idgenerator.rpc.IdGeneratorRpc;
import cn.bearspark.user.dto.UserSlimDTO;
import cn.bearspark.user.provider.dao.buffer.FanIdListBuffer;
import cn.bearspark.user.provider.dao.buffer.FollowerIdListBuffer;
import cn.bearspark.user.provider.dao.buffer.UserHashBuffer;
import cn.bearspark.user.provider.dao.co.UserCO;
import cn.bearspark.user.provider.dao.mapper.UserActiveMapper;
import cn.bearspark.user.provider.dao.po.UserBasePO;
import cn.bearspark.user.provider.dao.mapper.UserBaseMapper;
import cn.bearspark.user.dto.LoginRespDTO;
import cn.bearspark.user.dto.UserBaseInfoDTO;
import cn.bearspark.user.dto.UserSimpleDTO;
import cn.bearspark.user.enumeration.UserFailRespEnum;
import cn.bearspark.user.provider.service.UserBaseService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * TODO 如果关注/取关了用户，则需要将 关注者 id 缓存 和 粉丝 id 缓存 从 redis 中删除
 *
 * @author f
 */
@Service
public class UserBaseServiceImpl implements UserBaseService {

    /**
     * 设置默认生成的用户名的前缀
     */
    private static final String USERNAME_PREFIX = "bs_user_";

    /**
     * 设置默认用户头像的路径
     */
    private static final String DEFAULT_USER_AVATAR_URL = "http://<h>/bear-spark/file/download/default-avatar.gif";

    @DubboReference
    private IdGeneratorRpc idGeneratorRpc;

    private final UserBaseMapper userBaseMapper;
    private final UserActiveMapper userActiveMapper;

    private final UserHashBuffer userBuffer;
    private final FanIdListBuffer fanIdListBuffer;
    private final FollowerIdListBuffer followerIdListBuffer;

    public UserBaseServiceImpl(UserBaseMapper userBaseMapper,
                               UserActiveMapper userActiveMapper,
                               UserHashBuffer userBuffer,
                               FanIdListBuffer fanIdListBuffer,
                               FollowerIdListBuffer followerIdListBuffer) {
        this.userBaseMapper = userBaseMapper;
        this.userActiveMapper = userActiveMapper;
        this.userBuffer = userBuffer;
        this.fanIdListBuffer = fanIdListBuffer;
        this.followerIdListBuffer = followerIdListBuffer;
    }

    @Override
    public ResponseDTO<Object> initPassword(String phone, String password) {
        phone = DESUtil.encrypt(phone);
        password = DESUtil.encrypt(password);

        // 校验没有相同的手机号，如果有，则初始化密码失败
        if (userBaseMapper.countByPhone(phone) != 0) {
            return UserFailRespEnum.PHONE_EXIST.response();
        }

        // 封装用户基础数据对象
        UserBasePO userBasePO = new UserBasePO();
        Long userId = idGeneratorRpc.generateId(IdCodeEnum.USER_ID);
        userBasePO.setUserId(userId);
        userBasePO.setPhone(phone);
        userBasePO.setUsername(getDefaultUsername());
        userBasePO.setPassword(password);
        // 设置默认头像
        userBasePO.setAvatarUrl(DEFAULT_USER_AVATAR_URL);

        // 添加用户基础数据对象和活动对象
        userBaseMapper.insert(userBasePO);
        userActiveMapper.insert(userId);
        return ResponseDTO.success(userId);
    }

    // 获取默认生成的用户名，默认用户名为 默认用户名前缀 + 当前时间戳
    private static String getDefaultUsername() {
        return USERNAME_PREFIX + System.currentTimeMillis();
    }

    @Override
    public ResponseDTO<Object> modifyPassword(String phone, String password) {
        phone = DESUtil.encrypt(phone);
        password = DESUtil.encrypt(password);

        userBaseMapper.updatePasswordByPhone(phone, password);
        return ResponseDTO.success();
    }

    @Override
    public ResponseDTO<LoginRespDTO> login(String phone, String password) {
        phone = DESUtil.encrypt(phone);
        password = DESUtil.encrypt(password);

        // 查询是否存在指定的用户，如果不存在，则登录失败
        Long id = userBaseMapper.getIdByPhoneAndPassword(phone, password);
        if (id == null) {
            return UserFailRespEnum.NOT_EXIST_USER.response();
        }

        LoginRespDTO loginRespDTO = new LoginRespDTO();
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsKeyEnum.USER_ID.getKey(), id);
        loginRespDTO.setToken(JwtUtil.createJWT(claims));
        loginRespDTO.setTimestamp(System.currentTimeMillis());
        loginRespDTO.setExpire(JwtUtil.EXPIRE);
        return ResponseDTO.success(loginRespDTO);
    }

    @Override
    @AutoParseHost(UserBaseInfoDTO.class)
    public UserBaseInfoDTO getBaseInfo(long id) {
        return ConvertInfoUtil.convert(userBuffer.get(id), UserBaseInfoDTO.class);
    }

    @Override
    @AutoParseHost(UserSimpleDTO.class)
    public List<UserSimpleDTO> listFSimpleInfo(long userId) {
        return userBuffer.listSimpleInfo(followerIdListBuffer.listFollowerId(userId));
    }

    @Override
    @AutoParseHost(UserSlimDTO.class)
    public List<UserSlimDTO> listFSlimInfo(long userId) {
        return userBuffer.listSlimInfo(followerIdListBuffer.listFollowerId(userId));
    }

    @Override
    @AutoParseHost(UserSlimDTO.class)
    public List<UserSlimDTO> listFSlimInfoWithHappening(long userId) {
        return userBuffer.listSlimInfoWithHappening(followerIdListBuffer.listFollowerId(userId));
    }

    @Override
    @AutoParseHost(UserSlimDTO.class)
    public UserSlimDTO getSlimInfo(long userId) {
        return userBuffer.getSlimInfo(userId);
    }

    @Override
    @AutoParseHost(UserSlimDTO.class)
    public Map<Long, UserSlimDTO> mapSlimInfo(Set<Long> userIdSet) {
        return userBuffer.mapUserSlimInfo(userIdSet);
    }

    @Override
    @AutoParseHost(UserSlimDTO.class)
    public Map<Long, UserSlimDTO> mapSAFSlimInfoWithHappening(long userId) {
        List<Long> userIdList = followerIdListBuffer.listFollowerId(userId);
        userIdList.add(userId);
        return userBuffer.listSlimInfoWithHappening(userIdList).stream().collect(Collectors.toMap(
                UserSlimDTO::getUserId,
                Function.identity()
        ));
    }

    @Override
    public List<Long> listFansId(long userId) {
        return fanIdListBuffer.listFanId(userId);
    }

    @Override
    public long getHappeningNumByUserId(long userId) {
        UserCO userCO = userBuffer.get(userId);
        if (userCO == null) {
            return 0;
        }
        return userCO.getHappeningNum();
    }

    @Override
    public Map<Long, String> mapUsername(Set<Long> userIdSet) {
        return userBuffer.mapUsername(userIdSet);
    }
}
